package net.yla.smartbus.module.ba.right.right.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.sun.media.jfxmedia.logging.Logger;
import com.vip.vjtools.vjkit.collection.ListUtil;
import com.vip.vjtools.vjkit.mapper.BeanMapper;
import net.yla.smartbus.core.api.RequestCode;
import net.yla.smartbus.core.config.ProjectConstant;
import net.yla.smartbus.core.exception.AppException;
import net.yla.smartbus.module.ba.right.right.dto.RightsDTO;
import net.yla.smartbus.module.ba.right.right.form.RightsForm;
import net.yla.smartbus.module.ba.right.right.query.QueryOfActual;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import net.yla.smartbus.module.ba.right.right.entity.RightsDO;
import net.yla.smartbus.module.ba.right.right.mapper.RightsMapper;
import net.yla.smartbus.module.ba.right.right.service.RightsService;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * @Date: 2020-08-24 10:44
 * @Author: Being Nobody
 * @Version: 1.0
 */
@Service
public class RightsServiceImpl implements RightsService {

    @Resource
    private RightsMapper rightsMapper;

    @Override
    public int deleteByPrimaryKey(Integer rightId) {
        return rightsMapper.deleteByPrimaryKey(rightId);
    }

    @Override
    public int insert(RightsDO record) {
        return rightsMapper.insert(record);
    }

    @Override
    public int insertSelective(RightsDO record) {
        return rightsMapper.insertSelective(record);
    }

    @Override
    public RightsDO selectByPrimaryKey(Integer rightId) {
        return rightsMapper.selectByPrimaryKey(rightId);
    }

    @Override
    public int updateByPrimaryKeySelective(RightsDO record) {
        return rightsMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(RightsDO record) {
        return rightsMapper.updateByPrimaryKey(record);
    }

    /**
     * 获取角色所对应的权限
     * Hashtable:key: objectType  value >> key objectId value allow deny
     *
     * @param roles
     * @return Map<objectType, Map < objectId, rights>
     */
    @Override
    public Map<Integer, Map<Integer, Integer>> rights(List<Integer> roles) {
        Map<Integer, Map<Integer, Integer>> result = new Hashtable<>();
        if (roles != null && roles.size() > 0) {
            // 1 获取所有权限记录；
            List<RightsDO> rights = rightsMapper.rightsAll(roles);
            // 2 合并权限。
            this.mergeRights(rights, result);
        }
        return result;
    }

    /**
     * 查看指定角色有效权限
     *
     * @param query
     * @return
     */
    @Override
    public JSONObject actual(QueryOfActual query) {
        List<RightsDO> rolesDOList = rightsMapper.actual(query);
        //获取权限值
        int right = this.merge(rolesDOList);
        JSONObject result = new JSONObject();
        result.put("rightType", query.getRightType());
        result.put("actual", right);
        return result;
    }

    /**
     * 获取指定角色权限列表
     *
     * @param query
     * @return
     */
    @Override
    public List<RightsDTO> list(QueryOfActual query) {
        List<RightsDO> rolesDOList = rightsMapper.actual(query);
        List<RightsDTO> result = this.dispose(rolesDOList);

        return result;
    }

    /**
     * 保存指定角色的权限信息
     *
     * @param form
     * @return
     */
    @Override
    @Transactional
    public int save(RightsForm form) {
        List<RightsDTO> acl = form.getAcl();
        if (acl != null && !acl.isEmpty() && acl.size() > 0) {
            RightsDO rightsDO;
            for (RightsDTO dto : acl) {
                rightsDO = new RightsDO();
                BeanUtils.copyProperties(dto, rightsDO);
                rightsDO.setRoleId(form.getRole());
                rightsMapper.delete(rightsDO);
                if (rightsMapper.insertSelective(rightsDO) < 1) {
                    throw new AppException("保存失败", RequestCode.Operate_Tip);
                }
            }
        }
        return 1;
    }

    /**
     * 添加拥有的平台信息
     *
     * @param roleId
     * @param platformIds
     * @return
     */
    @Override
    public int addPlatformOfRole(Integer roleId, List<Integer> platformIds) {
        if (ListUtil.isEmpty(platformIds)) {
            return 0;
        }

        List<RightsDO> list = new ArrayList<>(platformIds.size());
        platformIds.forEach(s -> {
            RightsDO record = new RightsDO();
            record.setRoleId(roleId);
            // 允许权限
            record.setAllow(15);
            record.setObjectId(s);
            // 子系统对象
            record.setObjectType(1);
            record.setObjectName("子系统对象");
            record.setCreationTime(LocalDateTime.now());
            list.add(record);
        });
        return rightsMapper.insertList(list);
    }

    /**
     * 添加拥有的角色信息
     *
     * @param roleId
     * @param menuIds
     * @return
     */
    @Override
    public int addMenuOfRole(Integer roleId, List<Integer> menuIds) {
        if (ListUtil.isEmpty(menuIds)) {
            return 0;
        }

        List<RightsDO> list = new ArrayList<>(menuIds.size());
        menuIds.forEach(s -> {
            RightsDO record = new RightsDO();
            record.setRoleId(roleId);
            // 允许权限 菜單允许的权限 默认没有权限15
            record.setAllow(15);
            record.setObjectId(s);
            // 系统菜单
            record.setObjectType(3);
            record.setObjectName("系统菜单");
            record.setCreationTime(LocalDateTime.now());
            list.add(record);
        });
        return rightsMapper.insertList(list);
    }

    /**
     * @param roleIds
     * @return platformIds
     */
    @Override
    public List<Integer> platformIds(List<Integer> roleIds) {
        return rightsMapper.platformIds(roleIds);
    }

    /**
     * @param roleIds
     * @return menuIds
     */
    @Override
    public List<Integer> menuIds(List<Integer> roleIds) {
        return rightsMapper.menuIds(roleIds);
    }

    @Override
    public int updateByRoleId(Integer roleId) {
        return rightsMapper.updateByRoleId(roleId);
    }

    @Override
    public int deleteTrueByRoleId(Integer roleId) {
        return rightsMapper.deleteTrueByRoleId(roleId);
    }

    private List<RightsDTO> dispose(List<RightsDO> rolesDOList) {
        List<RightsDTO> result = null;
        if (ListUtil.isNotEmpty(rolesDOList) && rolesDOList.size() > 0) {
            result = new ArrayList<>(rolesDOList.size());
            for (RightsDO right : rolesDOList) {
                RightsDTO dto = BeanMapper.map(right, RightsDTO.class);
                // 权限
                dto.setActual(right.getAllow() & (~right.getDeny()));
                result.add(dto);
            }
        }

        return result;
    }

    /**
     * 合并权限
     *
     * @param rights 根据 ObjectType 和 ObjectId
     * @param result
     */
    private void mergeRights(List<RightsDO> rights, Map<Integer, Map<Integer, Integer>> result) {
        if (ListUtil.isNotEmpty(rights) && rights.size() > 0) {
            // 1过滤不同权限类型
            List<RightsDO> noSet = rights.stream().
                    filter(rights1 -> rights1.getObjectType() == ProjectConstant.NOSETTING).collect(Collectors.toList());
            List<RightsDO> subSystem = rights.stream().
                    filter(rights1 -> rights1.getObjectType() == ProjectConstant.SUBSYSTEM).collect(Collectors.toList());
            List<RightsDO> subModule = rights.stream().
                    filter(rights1 -> rights1.getObjectType() == ProjectConstant.SUBMODULE).collect(Collectors.toList());
            List<RightsDO> function = rights.stream().
                    filter(rights1 -> rights1.getObjectType() == ProjectConstant.FUNCTION).collect(Collectors.toList());
            // 2分组不同权限
            Map<Integer, List<RightsDO>> noSetCell = noSet.stream().collect(groupingBy(RightsDO::getObjectId));
            Map<Integer, List<RightsDO>> subSystemCell = subSystem.stream().collect(groupingBy(RightsDO::getObjectId));
            Map<Integer, List<RightsDO>> subModuleCell = subModule.stream().collect(groupingBy(RightsDO::getObjectId));
            Map<Integer, List<RightsDO>> functionCell = function.stream().collect(groupingBy(RightsDO::getObjectId));
            // 3合并不同权限
            result.put(ProjectConstant.NOSETTING, this.mergeRights(noSetCell));
            result.put(ProjectConstant.SUBSYSTEM, this.mergeRights(subSystemCell));
            result.put(ProjectConstant.SUBMODULE, this.mergeRights(subModuleCell));
            result.put(ProjectConstant.FUNCTION, this.mergeRights(functionCell));
        }
    }

    /**
     * 合并不同权限类型下的权限值
     *
     * @param rightsCell
     * @return
     */
    private Map<Integer, Integer> mergeRights(Map<Integer, List<RightsDO>> rightsCell) {
        Map<Integer, Integer> rightsValue = null;
        if (rightsCell != null) {
            rightsValue = new Hashtable<>();
            for (Integer key : rightsCell.keySet()) {
                List<RightsDO> rights = rightsCell.get(key);
                // 合并权限
                Integer value = this.merge(rights);
                rightsValue.put(key, value);
            }
        }
        return rightsValue;
    }

    /**
     * 合并不同权限值
     *
     * @param rights
     * @return
     */
    public Integer merge(List<RightsDO> rights) {
        int right = 0;
        if (ListUtil.isNotEmpty(rights) && rights.size() > 0) {
            // 1.allow权限
            List<Integer> allowList = rights.stream().map(rights1 -> rights1.getAllow()).collect(Collectors.toList());
            int allow = this.bitwiseOr(allowList);
            // 2.deny权限
            List<Integer> denyList = rights.stream().map(RightsDO::getDeny).collect(Collectors.toList());
            int deny = this.bitwiseOr(denyList);
            // 3.合并 allow & (~ deny)
            right = allow & (~deny);
        }

        return right;
    }

    /**
     * 按位或运算
     *
     * @param allowList
     * @return
     */
    private int bitwiseOr(List<Integer> allowList) {
        int i = 0;
        if (ListUtil.isNotEmpty(allowList) && allowList.size() > 0) {
            for (Integer right : allowList) {
                i = i | right;
            }
        }
        return i;
    }

}
